package com.bobochang.warehouse.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bobochang.warehouse.dto.*;
import com.bobochang.warehouse.entity.*;
import com.bobochang.warehouse.mapper.DailyConstructionMapper;
import com.bobochang.warehouse.page.Page;
import com.bobochang.warehouse.service.*;
import com.bobochang.warehouse.mapper.ConstructionDetailsMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author bobochang
* @description 针对表【construction_details(施工明细表)】的数据库操作Service实现
* @createDate 2024-06-25 10:29:22
*/
@Service
@Slf4j
public class DailyConstructionServiceImpl extends ServiceImpl<DailyConstructionMapper, DailyConstruction>
    implements DailyConstructionService {

    @Autowired
    private ConstructionDetailsMapper constructionDetailsMapper;
    @Autowired
    private ContractService contractService;
    @Autowired
    private ConstructionDetailsService constructionDetailsService;
    @Autowired
    private ConstructionTypeServiceImpl constructionTypeService;
    @Autowired
    private LocationConstructionService locationConstructionService;
    @Autowired
    private ProductService productService;

    @Override
    public Page queryConstructionPage(Page page, ConstructionDetailsDto cd) {
        // 查询施工明细总行数
        log.info(cd.toString());
        int total = constructionDetailsMapper.selectConstructionCount(cd);
        page.setTotalNum(total);

        List<Integer> productIds = null;
        List<DailyConstruction> constructionList = null;

        if(cd.getProductId() != null){
            Product product = productService.getById(cd.getProductId());
            productIds = constructionTypeService.list(new LambdaQueryWrapper<ConstructionType>().eq(ConstructionType::getProductId, product.getProductId())).stream().filter(Objects::nonNull).map(ConstructionType::getId).collect(Collectors.toList());
            if(productIds.size() != 0){
                constructionList = baseMapper.selectList(
                        new LambdaQueryWrapper<DailyConstruction>()
                                .eq(cd.getConstructionTypeId() != null, DailyConstruction::getConstructionTypeId, cd.getConstructionTypeId())
                                .in(productIds != null, DailyConstruction::getConstructionTypeId, productIds)
                                .eq(cd.getLocationId() != null, DailyConstruction::getLocationId, cd.getLocationId())
                                .eq(cd.getContractId() != null, DailyConstruction::getContractId, cd.getContractId())
                                .eq(cd.getDate() != null, DailyConstruction::getDate, cd.getDate())
                                .last("limit "+page.getLimitIndex() + ", " + page.getPageSize())
                );
            }else {
                page.setResultList(null);
                return page;
            }
        }else {
            constructionList = baseMapper.selectList(
                    new LambdaQueryWrapper<DailyConstruction>()
                            .eq(cd.getConstructionTypeId() != null, DailyConstruction::getConstructionTypeId, cd.getConstructionTypeId())
                            .eq(cd.getLocationId() != null, DailyConstruction::getLocationId, cd.getLocationId())
                            .eq(cd.getContractId() != null, DailyConstruction::getContractId, cd.getContractId())
                            .eq(cd.getDate() != null, DailyConstruction::getDate, cd.getDate())
                            .last("limit "+page.getLimitIndex() + ", " + page.getPageSize())
            );
        }

        // 分页查询施工明细
        if(constructionList == null){
            page.setResultList(null);
            return page;
        }
        constructionList.stream().filter(Objects::nonNull).forEach(c -> {
            c.setContract(contractService.getOne(new LambdaQueryWrapper<Contract>().eq(Contract::getContractId,c.getContractId())));
            c.setConstructionType(constructionTypeService.getById(c.getConstructionTypeId()));
            if(c.getConstructionType().getProductId() != null){
                c.getConstructionType().setProductName(productService.getById(c.getConstructionType().getProductId()).getProductName());
            }
            c.setLocationConstruction(locationConstructionService.getById(c.getLocationId()));
            c.setConstructionDetails(constructionDetailsService.getOne(new LambdaQueryWrapper<ConstructionDetails>().eq(ConstructionDetails::getDailyConstructionId, c.getId())));
        });

        page.setResultList(constructionList);
        return page;
    }

    @Override
    public ConstructionDetailsCollectDto findCollect(Contract c) {
        Contract contract = c.getContractId() != null? contractService.findContractById(c.getContractId()) : contractService.getOne(new LambdaQueryWrapper<Contract>().like(Contract::getContractName,c.getContractName()));
        ConstructionDetailsCollectDto constructionDetailsCollectDto = new ConstructionDetailsCollectDto(0);
        constructionDetailsCollectDto.setContract(contract);

        List<LocationConstruction> locationConstructions = locationConstructionService.list(new LambdaQueryWrapper<LocationConstruction>().eq(LocationConstruction::getContractId, contract.getContractId()));
        //List<ConstructionType> constructionType = constructionTypeService.listByContractId(contract.getContractId());

        locationConstructions.stream().filter(Objects::nonNull).forEach(l -> {
            // 施工位置
            ConstructionDetailsCollectDto c1 = new ConstructionDetailsCollectDto(1);
            c1.setLocationId(l.getId());
            c1.setLocationName(l.getLocationName());

            List<ConstructionDetailsCollectDto> constructionDetailsCollectDtos = baseMapper.collect(contract.getContractId(),l.getId());

            c1.setCollectLength(constructionDetailsCollectDtos.stream()
                    .filter(cc -> cc.getMeasurement().equals("施工长度"))
                    .map(ConstructionDetailsCollectDto::getNumber)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            c1.setCollectNumberGe(constructionDetailsCollectDtos.stream()
                    .filter(cc -> cc.getMeasurement().equals("施工数量") && cc.getUnit() == 90)
                    .map(ConstructionDetailsCollectDto::getNumber)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            c1.setCollectNumberGe(constructionDetailsCollectDtos.stream()
                    .filter(cc -> cc.getMeasurement().equals("施工数量") && cc.getUnit() == 91)
                    .map(ConstructionDetailsCollectDto::getNumber)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));


            c1.setConstructionDetailsCollectDtos(constructionDetailsCollectDtos);
            constructionDetailsCollectDto.getConstructionDetailsCollectDtos().add(c1);
        });

        return constructionDetailsCollectDto;
    }

    @Override
    @Transactional
    public Result add(NewConstructionDetailsDto newConstructionDetailsDto) {
        // 施工位置
        if(newConstructionDetailsDto.getLocationId() == null){
            LocationConstruction locationConstruction = locationConstructionService.getOne(new LambdaQueryWrapper<LocationConstruction>()
                    .eq(LocationConstruction::getContractId, newConstructionDetailsDto.getContractId())
                    .eq(newConstructionDetailsDto.getNewLocationName() != null, LocationConstruction::getLocationName, newConstructionDetailsDto.getNewLocationName())
            );
            if(locationConstruction != null){
                return Result.err(Result.CODE_ERR_BUSINESS,"施工位置错误");
            }
            locationConstruction = new LocationConstruction();
            locationConstruction.setLocationName(newConstructionDetailsDto.getNewLocationName());
            locationConstruction.setContractId(newConstructionDetailsDto.getContractId());
            locationConstructionService.save(locationConstruction);
            newConstructionDetailsDto.setLocationId(locationConstruction.getId());
        }
        // 检查上报时间
        Contract contract = contractService.getOne(new LambdaQueryWrapper<Contract>().eq(Contract::getContractId, newConstructionDetailsDto.getContractId()));
        if(contract == null){
            return Result.err(Result.CODE_ERR_BUSINESS, "合同异常");
        }
        if(contract.getStartTime().compareTo(newConstructionDetailsDto.getDate()) > 0 || contract.getEndTime().compareTo(newConstructionDetailsDto.getDate()) < 0){
            return Result.err(Result.CODE_ERR_BUSINESS, "上报时间超出合同期限");
        }

        //施工情况
        DailyConstruction dailyConstruction = new DailyConstruction();
        dailyConstruction.setConstructionTypeId(newConstructionDetailsDto.getConstructionTypeId());
        dailyConstruction.setContractId(newConstructionDetailsDto.getContractId());
        dailyConstruction.setLocationId(newConstructionDetailsDto.getLocationId());
        dailyConstruction.setDate(newConstructionDetailsDto.getDate());
        baseMapper.insert(dailyConstruction);

        //施工明细
        ConstructionDetails constructionDetails = new ConstructionDetails();
        constructionDetails.setNumber(newConstructionDetailsDto.getNumber());
        constructionDetails.setDailyConstructionId(dailyConstruction.getId());
        constructionDetails.setRemark(newConstructionDetailsDto.getRemark());
        constructionDetails.setWeather(newConstructionDetailsDto.getWeather());
        constructionDetails.setNumberProduct(newConstructionDetailsDto.getNumberProduct());
        constructionDetailsMapper.insert(constructionDetails);

        return Result.ok();
    }

    @Override
    public Result updateConstruction(NewConstructionDetailsDto newConstructionDetailsDto) {
        // 修改位置
        LocationConstruction locationConstruction;
        if(newConstructionDetailsDto.getLocationId() == null && newConstructionDetailsDto.getNewLocationName() != null){
            locationConstruction = locationConstructionService.getOne(new LambdaQueryWrapper<LocationConstruction>().eq(LocationConstruction::getLocationName, newConstructionDetailsDto.getNewLocationName()));
            if(locationConstruction != null){
                return Result.err(Result.CODE_ERR_BUSINESS, "位置重复错误");
            }
            locationConstruction = new LocationConstruction();
            locationConstruction.setLocationName(newConstructionDetailsDto.getNewLocationName());
            locationConstructionService.save(locationConstruction);
            newConstructionDetailsDto.setLocationId(locationConstruction.getId());
        }
        // 检查时间
        Contract contract = contractService.getOne(new LambdaQueryWrapper<Contract>().eq(Contract::getContractId, newConstructionDetailsDto.getContractId()));
        if(contract == null){
            return Result.err(Result.CODE_ERR_BUSINESS, "合同异常");
        }
        if(contract.getStartTime().compareTo(newConstructionDetailsDto.getDate()) > 0 || contract.getEndTime().compareTo(newConstructionDetailsDto.getDate()) < 0){
            return Result.err(Result.CODE_ERR_BUSINESS, "上报时间超出合同期限");
        }

        DailyConstruction dailyConstruction = new DailyConstruction();
        dailyConstruction.setId(newConstructionDetailsDto.getDailyConstructionId());
        dailyConstruction.setContractId(newConstructionDetailsDto.getContractId());
        dailyConstruction.setLocationId(newConstructionDetailsDto.getLocationId());
        dailyConstruction.setConstructionTypeId(newConstructionDetailsDto.getConstructionTypeId());

        baseMapper.updateById(dailyConstruction);

        LambdaUpdateWrapper<ConstructionDetails> queryWrapper = new LambdaUpdateWrapper<ConstructionDetails>()
                .eq(ConstructionDetails::getDailyConstructionId, dailyConstruction.getId())
                .set(ConstructionDetails::getNumber, newConstructionDetailsDto.getNumber())
                .set(ConstructionDetails::getWeather, newConstructionDetailsDto.getWeather())
                .set(ConstructionDetails::getRemark, newConstructionDetailsDto.getRemark())
                .set(newConstructionDetailsDto.getProductId() == null, ConstructionDetails::getNumberProduct, null)
                .set(newConstructionDetailsDto.getNumberProduct() == null, ConstructionDetails::getNumberProduct, null);
        constructionDetailsService.update(queryWrapper);
        return Result.ok();
    }

    @Override
    public Result delete(Integer constructionId) {
        DailyConstruction dailyConstruction = baseMapper.selectById(constructionId);
        if(dailyConstruction == null){
            return Result.err(Result.CODE_ERR_BUSINESS, "删除失败");
        }

        int locationNumber = this.count(new LambdaQueryWrapper<DailyConstruction>()
                .eq(DailyConstruction::getLocationId, dailyConstruction.getLocationId())
                .eq(DailyConstruction::getContractId, dailyConstruction.getContractId())
                .ne(DailyConstruction::getId, dailyConstruction.getId())
        );
        if(locationNumber < 1){
            locationConstructionService.remove(new LambdaQueryWrapper<LocationConstruction>()
                    .eq(LocationConstruction::getId, dailyConstruction.getLocationId()));
        }
        baseMapper.delete(new LambdaQueryWrapper<DailyConstruction>()
                .eq(DailyConstruction::getId, dailyConstruction.getId()));
        return Result.ok();
    }

    @Override
    public List<ConstructionDetailsCollectDto> findCollectList(Contract c) {
        // 合同
        Contract contract = c.getContractId() != null? contractService.findContractById(c.getContractId()) : contractService.getOne(new LambdaQueryWrapper<Contract>().like(Contract::getContractName,c.getContractName()));
        List<ConstructionDetailsCollectDto> constructionDetailsCollectDto = new ArrayList<>();
        // 全部位置
        List<LocationConstruction> locationConstructions = locationConstructionService.list(new LambdaQueryWrapper<LocationConstruction>().eq(LocationConstruction::getContractId, contract.getContractId()));
        // 按位置分类查
        locationConstructions.stream().filter(Objects::nonNull).forEach(l -> {
            // 全部施工明细
            List<ConstructionDetailsCollectDto> constructionDetailsCollectDtos = baseMapper.collect(contract.getContractId(),l.getId());
            // 位置信息
            constructionDetailsCollectDtos.stream().filter(Objects::nonNull).forEach(cc -> {
                cc.setLocationId(l.getId());
                cc.setLocationName(l.getLocationName());
                cc.setContract(contract);
                cc.setNumberByLocation(constructionDetailsCollectDtos.size());
            });

            // 合计行
            ConstructionDetailsCollectDto constructionDetailsCollectDto1 = new ConstructionDetailsCollectDto(2);
            constructionDetailsCollectDto1.setCollectLength(constructionDetailsCollectDtos.stream()
                    .filter(cc -> cc.getMeasurement().equals("施工长度"))
                    .map(ConstructionDetailsCollectDto::getNumber)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            constructionDetailsCollectDto1.setCollectNumberGe(constructionDetailsCollectDtos.stream()
                    .filter(cc -> cc.getMeasurement().equals("施工数量") && cc.getUnit() == 90)
                    .map(ConstructionDetailsCollectDto::getNumber)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            constructionDetailsCollectDto1.setCollectNumberM2(constructionDetailsCollectDtos.stream()
                    .filter(cc -> cc.getMeasurement().equals("施工数量") && cc.getUnit() == 91)
                    .map(ConstructionDetailsCollectDto::getNumber)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            constructionDetailsCollectDto1.setCollectNumberProduct(constructionDetailsCollectDtos.stream()
                    .filter(cc -> cc.getProductId() != null)
                    .map(ConstructionDetailsCollectDto::getNumberProduct)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            constructionDetailsCollectDto1.setLocationName("合计");

            constructionDetailsCollectDto.addAll(constructionDetailsCollectDtos);
            constructionDetailsCollectDto.add(constructionDetailsCollectDto1);
        });
        return constructionDetailsCollectDto;
    }

    public List<ProductCollectDto> collectProduct(String cid, Date date){
        List<ProductCollectDto> productCollectDtos = new ArrayList<>();
        List<Product> products = productService.list();

        if(cid != null && !cid.equals("")){
            if(date == null){
                date = baseMapper.findDataByCid(cid);
            }
            List<ProductCollectDto> productCollectDtos1 = baseMapper.selectCollectProduct(cid, date);
            if(productCollectDtos1.size() == 0){
                ProductCollectDto productCollectDto = new ProductCollectDto(products);
                productCollectDto.setDate(date);
                productCollectDtos.add(productCollectDto);
                return productCollectDtos;
            }

            ProductCollectDto productCollectDto = new ProductCollectDto(products);
            productCollectDto.setProjectName(productCollectDtos1.get(0).getProjectName());
            productCollectDto.setCompany(productCollectDtos1.get(0).getCompany());
            productCollectDto.setDate(productCollectDtos1.get(0).getDate());

            productCollectDtos1.stream().filter(Objects::nonNull).forEach(p -> {
                productCollectDto.setNumber1(p.getProductId(), p.getNumber());
            });
            productCollectDtos.add(productCollectDto);
        }else {
            if(date == null){
                date = baseMapper.findData();
            }
            List<ProductCollectDto> productCollectDtos1 = baseMapper.selectCollectProduct2(date);
            if(productCollectDtos1.size() == 0){
                ProductCollectDto productCollectDto = new ProductCollectDto(products);
                productCollectDto.setDate(date);
                productCollectDtos.add(productCollectDto);
                return productCollectDtos;
            }
            // 项目数
            Set<Integer> ids = productCollectDtos1.stream().filter(Objects::nonNull).map(ProductCollectDto::getContactId).collect(Collectors.toSet());
            ids.forEach(i -> {
                ProductCollectDto productCollectDto = new ProductCollectDto(products);
                productCollectDto.setProjectName(productCollectDtos1.stream().filter(p -> p.getContactId().equals(i)).findFirst().get().getProjectName());
                productCollectDto.setCompany(productCollectDtos1.stream().filter(p -> p.getContactId().equals(i)).findFirst().get().getCompany());
                productCollectDto.setDate(productCollectDtos1.stream().filter(p -> p.getContactId().equals(i)).findFirst().get().getDate());

                    productCollectDtos1.stream()
                        .filter(Objects::nonNull)
                        .filter(p -> p.getContactId().equals(i))
                        .forEach(p -> {
                            productCollectDto.setNumber1(p.getProductId(), p.getNumber());
                        });
                productCollectDtos.add(productCollectDto);
            });
        }
        return productCollectDtos;
    }

    @Override
    public List<CollectSettleAccountsDto> collectSettleAccounts(String contractId, String startTime, String endTime) {
        boolean f = true;

        if(contractId == null || contractId.equals("")){
            return null;
        }
        if(startTime == null){
            f = false;
            LambdaQueryWrapper<Contract> contractLambdaQueryWrapper = new LambdaQueryWrapper<Contract>().eq(Contract::getContractId, contractId);
            Contract contract = contractService.getOne(contractLambdaQueryWrapper);
            startTime = new SimpleDateFormat("yyyy-MM-dd").format(contract.getStartTime());
            endTime = new SimpleDateFormat("yyyy-MM-dd").format(contract.getEndTime());
        }
        List<CollectSettleAccountsDto> collectSettleAccountsDtoList = baseMapper.selectCollectSettleAccountsDtoList(contractId, startTime, endTime);

        boolean finalF = f;
        String finalStartTime = startTime;
        String finalEndTime = endTime;
        collectSettleAccountsDtoList.stream().filter(Objects::nonNull).forEach(c -> {
            c.setCategory("计量");
            c.setNewMoney(c.getNewNumber().multiply(c.getUnitPrice()).setScale(4, RoundingMode.HALF_UP));
            if(!finalF){
                c.setOldNumber(c.getNumber());
                c.setOldMoney(c.getMoney());
            }else {
                BigDecimal decimal = baseMapper.selectOldNumber(contractId, finalStartTime, c.getTypeId());
                c.setOldNumber(c.getNumber().subtract(decimal == null? BigDecimal.valueOf(0) : decimal).setScale(4, RoundingMode.HALF_UP));
                c.setOldMoney(c.getOldNumber().multiply(c.getUnitPrice()).setScale(4, RoundingMode.HALF_UP));
            }
            BigDecimal temp = baseMapper.selectEndNumber(contractId, finalEndTime, c.getTypeId());
            c.setEndNumber(temp == null? BigDecimal.valueOf(0): temp);
            c.setEndMoney(c.getEndNumber().multiply(c.getUnitPrice()).setScale(4, RoundingMode.HALF_UP));
            c.setProportion(c.getEndNumber().divide(c.getNumber(), 4, RoundingMode.HALF_UP));
        });

        // 合计
        CollectSettleAccountsDto collectSettleAccountsDto = new CollectSettleAccountsDto();
        collectSettleAccountsDto.setCategory("计量");
        collectSettleAccountsDto.setType("合计");
        collectSettleAccountsDto.setMoney(collectSettleAccountsDtoList.stream().map(CollectSettleAccountsDto::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add));
        collectSettleAccountsDto.setNewMoney(collectSettleAccountsDtoList.stream().map(CollectSettleAccountsDto::getNewMoney).reduce(BigDecimal.ZERO, BigDecimal::add));
        collectSettleAccountsDto.setOldMoney(collectSettleAccountsDtoList.stream().map(CollectSettleAccountsDto::getOldMoney).reduce(BigDecimal.ZERO, BigDecimal::add));
        collectSettleAccountsDto.setEndMoney(collectSettleAccountsDtoList.stream().map(CollectSettleAccountsDto::getEndMoney).reduce(BigDecimal.ZERO, BigDecimal::add));
        collectSettleAccountsDtoList.add(collectSettleAccountsDto);

        // 扣款

        // 应支付
        CollectSettleAccountsDto c2 = new CollectSettleAccountsDto();
        c2.setCategory("应支付");
        c2.setType("合计");
        collectSettleAccountsDtoList.add(c2);

        return collectSettleAccountsDtoList;
    }
}




